#!/bin/bash
# k3s-oss-backup-corrected.sh
# 基于Kubernetes环境的备份脚本（支持容器内执行）

set -euo pipefail

##############################
# 0. 基础配置和日志
##############################
LOG="/var/log/k3s-oss-backup-corrected.log"
exec >>"$LOG" 2>&1

echo "===== $(date) K3s集群备份开始 ====="

BUCKET="dingchen-zd-oss"
ENDPOINT="oss-cn-wulanchabu-internal.aliyuncs.com"
ACCESS_KEY_ID="LTAI5tGR6YF1BpRRpYVfbiYT"
ACCESS_KEY_SECRET="IYTLimPq9HHYmwtVtXbbKLkGAZQbTa"

DATE=$(date +%Y%m%d)
TIME=$(date +%H%M%S)
BACKUP_DIR="/tmp/k3s-backup-${DATE}-${TIME}"
mkdir -p "$BACKUP_DIR"


echo "===== $(date) 获取密码 ====="
MYSQL_ROOT_PASSWORD=$(kubectl get secret -n db mysql-secret -o jsonpath='{.data.root-password}' | base64 -d)
REDIS_PASSWORD=$(kubectl get secret -n redis redis-auth -o jsonpath='{.data.redis-password}' | base64 -d)

# 验证密码获取
if [[ -z "$MYSQL_ROOT_PASSWORD" || -z "$REDIS_PASSWORD" ]]; then
    echo "❌ 密码获取失败"
    exit 1
fi
echo "✅ 密码获取成功"

##############################
# 1. 组件健康检查
##############################
check_component_health() {
    echo "检查MySQL状态..."
    kubectl get pods -n db -l app=mysql > /dev/null 2>&1 || { echo "❌ MySQL Pod不存在"; return 1; }

    echo "检查Redis状态..."
    kubectl get pods -n redis -l app=redis > /dev/null 2>&1 || { echo "❌ Redis Pod不存在"; return 1; }

    echo "验证Redis认证..."
    kubectl exec -n redis deployment/redis -- redis-cli -a "$REDIS_PASSWORD" PING > /dev/null 2>&1 || { echo "❌ Redis认证失败"; return 1; }

    echo "✅ 所有组件健康检查通过"
    return 0
}

echo "===== $(date) 组件健康检查 ====="
if ! check_component_health; then
    echo "❌ 组件健康检查失败，停止备份"
    exit 1
fi


##############################
# 2. 备份函数
##############################

backup_mysql() {
  echo "[mysql] 在Pod中导出数据库"
   mysql_pod=$(kubectl get pod -n db -l app=mysql -o jsonpath='{.items[0].metadata.name}')

  kubectl exec -n db "$mysql_pod" -- sh -c \
    "mysqldump -u root -p'$MYSQL_ROOT_PASSWORD' --all-databases --single-transaction --routines --triggers" \
    | gzip > "$BACKUP_DIR/mysql-backup-${DATE}-${TIME}.sql.gz"

  # 验证备份
  if gunzip -t "$BACKUP_DIR/mysql-backup-${DATE}-${TIME}.sql.gz"; then
    echo "✅ MySQL备份验证成功"
  else
    echo "❌ MySQL备份验证失败"
    return 1
  fi
}

backup_redis() {
  echo "[redis] 在Pod中备份数据"
   redis_pod=$(kubectl get pod -n redis -l app=redis -o jsonpath='{.items[0].metadata.name}')

  # 保存Redis数据
  kubectl exec -n redis "$redis_pod" -c redis -- \
    redis-cli -a "$REDIS_PASSWORD" --no-auth-warning SAVE

  # 在Pod中打包数据
  kubectl exec -n redis "$redis_pod" -c redis -- \
    tar -czf /tmp/redis-backup-${DATE}-${TIME}.tar.gz -C /data .

  # 复制到宿主机
  kubectl cp redis/"$redis_pod":/tmp/redis-backup-${DATE}-${TIME}.tar.gz \
    "$BACKUP_DIR/redis-backup-${DATE}-${TIME}.tar.gz"

  # 清理Pod中的临时文件
  kubectl exec -n redis "$redis_pod" -c redis -- \
    rm -f /tmp/redis-backup-${DATE}-${TIME}.tar.gz
}

backup_mosquitto() {
  echo "[mosquitto] 在Pod中备份数据"
   mosquitto_pod=$(kubectl get pod -l app=mosquitto -o jsonpath='{.items[0].metadata.name}')

  # 在Pod中打包数据（假设数据目录为/mosquitto/data）
  kubectl exec "$mosquitto_pod" -- \
    tar -czf /tmp/mosquitto-backup-${DATE}-${TIME}.tar.gz -C /mosquitto/data .

  # 复制到宿主机
  kubectl cp default/"$mosquitto_pod":/tmp/mosquitto-backup-${DATE}-${TIME}.tar.gz \
    "$BACKUP_DIR/mosquitto-backup-${DATE}-${TIME}.tar.gz"

  # 清理Pod中的临时文件
  kubectl exec "$mosquitto_pod" -- \
    rm -f /tmp/mosquitto-backup-${DATE}-${TIME}.tar.gz
}

backup_etcd() {
  echo "[etcd] 创建K3s快照"

  # 使用K3s内置的etcd快照功能
  if ! k3s etcd-snapshot save --snapshot-compress; then
    echo "❌ etcd快照创建失败"
    return 1
  fi

  # 找到最新快照（修正查找模式）
  latest_snapshot=$(find /var/lib/rancher/k3s/server/db/snapshots \
      -name "etcd-snapshot-*" -o -name "on-demand-*" | sort -r | head -1)

  if [[ -n "$latest_snapshot" && -f "$latest_snapshot" ]]; then
    cp "$latest_snapshot" "$BACKUP_DIR/etcd-snapshot-${DATE}-${TIME}"
    echo "✅ etcd快照备份完成: $(basename $latest_snapshot)"
  else
    echo "❌ 未找到etcd快照文件"
    return 1
  fi
}

backup_argocd() {
  echo "[argocd] 备份配置资源"
   argocd_backup_dir="$BACKUP_DIR/argocd"
  mkdir -p "$argocd_backup_dir"

  # 备份关键ArgoCD资源
  kubectl get -n argocd applications -o yaml > "$argocd_backup_dir/applications.yaml"
  kubectl get -n argocd appprojects -o yaml > "$argocd_backup_dir/appprojects.yaml"
  kubectl get -n argocd configmaps -o yaml > "$argocd_backup_dir/configmaps.yaml"
  kubectl get -n argocd secrets -o yaml > "$argocd_backup_dir/secrets.yaml"

  # 打包配置
  tar -czf "$BACKUP_DIR/argocd-backup-${DATE}-${TIME}.tar.gz" -C "$argocd_backup_dir" .

  # 清理临时目录
  rm -rf "$argocd_backup_dir"
}

##############################
# 3. 依次执行备份
##############################
echo "===== $(date) K3s集群备份开始 ====="

# 检查Kubernetes连接
if ! kubectl cluster-info > /dev/null 2>&1; then
  echo "❌ 无法连接到Kubernetes集群"
  exit 1
fi

# 执行备份（带错误处理）
backup_functions=(
  backup_etcd
  backup_mysql
  backup_redis
  backup_mosquitto
  backup_argocd
)

for func in "${backup_functions[@]}"; do
  if ! $func; then
    echo "❌ $func 备份失败"
    # 继续执行其他备份，不退出
  fi
done

echo "===== $(date) 本地备份完成 ====="

# 显示所有备份文件
echo ""
echo "备份文件列表:"
ls -lh "$BACKUP_DIR/" 2>/dev/null || echo "备份目录为空"
echo ""

##############################
# 4. 上传函数
##############################
upload_latest() {
   pattern="$1" oss_path="$2" comp="$3"
   latest=$(ls -t $pattern 2>/dev/null | head -n1)

  if [[ -n "$latest" && -f "$latest" ]]; then
    echo "[$comp] 上传 $latest"
    if ossutil64 cp -f "$latest" "$oss_path" \
      --endpoint "$ENDPOINT" \
      --access-key-id "$ACCESS_KEY_ID" \
      --access-key-secret "$ACCESS_KEY_SECRET"; then
      echo "✅ [$comp] 上传完成"
    else
      echo "❌ [$comp] 上传失败"
      return 1
    fi
  else
    echo "⚠️  [$comp] 未找到备份文件: $pattern"
    return 1
  fi
}

##############################
# 5. 上传到OSS
##############################
echo "===== $(date) OSS上传开始 ====="

# 创建OSS目录结构（如果需要）
upload_latest "$BACKUP_DIR/mysql-backup-*.sql.gz" \
  "oss://${BUCKET}/k3s-backup/mysql/daily/${DATE}/" "mysql"

upload_latest "$BACKUP_DIR/redis-backup-*.tar.gz" \
  "oss://${BUCKET}/k3s-backup/redis/daily/${DATE}/" "redis"

upload_latest "$BACKUP_DIR/mosquitto-backup-*.tar.gz" \
  "oss://${BUCKET}/k3s-backup/mosquitto/weekly/$(date +%Y-W%U)/" "mosquitto"

etcd_file=$(find "$BACKUP_DIR" -maxdepth 1 -type f \( -name "etcd-snapshot-*" -o -name "on-demand-*.zip" \) | head -n1)
if [[ -f "$etcd_file" ]]; then
  echo "[etcd] 上传 $etcd_file"
  if ossutil64 cp -f "$etcd_file" "oss://${BUCKET}/k3s-backup/etcd/daily/${DATE}/" \
    --endpoint "$ENDPOINT" \
    --access-key-id "$ACCESS_KEY_ID" \
    --access-key-secret "$ACCESS_KEY_SECRET"; then
    echo "✅ [etcd] 上传完成"
  else
    echo "❌ [etcd] 上传失败"
  fi
else
  echo "⚠️  [etcd] 未找到快照文件"
fi

argocd_pattern="$BACKUP_DIR/argocd-backup-${DATE}-${TIME}.tar.gz"
echo "[debug] 查找argocd文件: $argocd_pattern"
if [[ -f "$argocd_pattern" ]]; then
  echo "[argocd] 上传 $argocd_pattern"
  if ossutil64 cp -f "$argocd_pattern" "oss://${BUCKET}/k3s-backup/argocd/daily/${DATE}/" \
    --endpoint "$ENDPOINT" \
    --access-key-id "$ACCESS_KEY_ID" \
    --access-key-secret "$ACCESS_KEY_SECRET"; then
    echo "✅ [argocd] 上传完成"
  else
    echo "❌ [argocd] 上传失败"
  fi
else
  echo "⚠️  [argocd] 文件不存在: $argocd_pattern"
fi

##############################
# 6. 验证和清理
##############################
echo "===== $(date) 上传验证 ====="
ossutil64 ls "oss://${BUCKET}/k3s-backup/" --recursive \
  --endpoint "$ENDPOINT" \
  --access-key-id "$ACCESS_KEY_ID" \
  --access-key-secret "$ACCESS_KEY_SECRET" | grep "$DATE" || true

echo "===== $(date) 清理本地备份 ====="
rm -rf "$BACKUP_DIR"

echo "✅ 备份完成！备份文件已上传到OSS"
echo "===== $(date) 全部完成 ====="